home *** CD-ROM | disk | FTP | other *** search
- /* file: FC_EXEC.PL {main forward chainer} */
- /* *************
- M I K E
- *************
- Micro Interpreter for Knowledge Engineering
- {written in Edinburgh-syntax Prolog}
-
- MIKE: Copyright (c) 1989, 1990 The Open University (U.K.)
-
- MIKE is intended for educational purposes, and may not
- be sold as or incorporated in a commercial product without
- written permission from: The Copyrights Officer, Open University,
- Milton Keynes MK7 6AA, U.K.
-
- The Open University accepts no responsibility for any legal or other
- consequences which may arise directly or indirectly as a result of the
- use of all or parts of the contents of this program.
-
- This software accompanies Open University Study Pack PD624, 'KNOWLEDGE
- ENGINEERING'. Complete sets of study pack materials may be obtained from:
-
- Learning Materials Sales Office
- The Open University
- P.O. Box 188
- Milton Keynes MK7 6DH, U.K.
-
- Tel: [+44] (908) 653338
- Fax: [+44] (908) 653744
- */
- /*============== F O R W A R D C H A I N I N G E X E C U T I V E ======= */
-
- /* To keep the file ENGINE.PL a manageable size, one part of it (the
- main forward-chaining executive control loop) has been placed here. */
-
- /* The main interpreter runs in a loop inside forward_chain. The logic
- is deliberately simple, hence vulnerable to rapid deterioration on large
- rule sets. ALL stored rules are gathered up using findall/0, and then
- (of those rules), those whose left-hand-side conditions ALL succeed are
- regarded as the 'conflict set'. This latter set is then 'whittled down'
- using resolve_conflicts/4. The unique winner then has its right-hand-side
- actions executed using perform/4. Optimisation of this definition would
- yield big rewards, especially if Rete network or other type of rule
- compilation were employed */
-
- /* The essential auxilliary procedures all_in_wm, resolve_conflicts,
- and perform are defined in ENGINE.PL */
-
- forward_chain:-
- repeat, /* cycle until halt is encountered... */
- fc_do_one_cycle(NewWME), /* workhorse: computes new WM each cycle */
- fc_halt_else_loop(NewWME). /* bails out only if 'halt' is in WM */
-
- /* cleanup below is invoked by initialise and part_initialise */
- fc_reset_history :-
- abolish('pd624 fc_history',3), /* tidy up stuff for ?- show history. */
- abolish('pd624 current cycle is',1), /* ditto */
- asserta('pd624 current cycle is'(0)). /* ditto */
-
- fc_do_one_cycle(NewWME) :- /* NewWME is OUTPUT (New Working Memory Elements) */
- fc_update_counters(WME), /* fetch current WM, update cycle counter */
- findall1((rule RULE forward if COND then ACTIONS), /* given this pattern */
- fc_good_potential(RULE,COND,ACTIONS), /* round up candidates */
- ConfSet), /* put into conflict set */
- fc_pick_one_and_do_it(ConfSet,WME,NewWME), /* choose one winner */
- !.
-
-
- fc_update_counters(WME) :- /* cycle counter gets globally incremented */
- retract('pd624 wme'(WME)), /* this retrieves latest working memory */
- retract('pd624 current cycle is'(CURRCYCLENUM)),
- NEWCYCLENUM is CURRCYCLENUM + 1,
- asserta('pd624 current cycle is'(NEWCYCLENUM)).
-
- fc_pick_one_and_do_it(ConfSet,WME,NewWME) :- /* third arg is OUTPUT */
- current_conflict_resolution_strategy(Strategy),
- when_enabled('show conflict set' for ConfSet),
- resolve_conflicts(ConfSet, /* whole set goes in, only next one comes out */
- (rule Rule forward if Cond then Actions), /* This one */
- WME,
- Strategy),
- when_enabled('show conflict winner' for Rule), /* shorthand winner */
- when_enabled('show history on request' for [Rule,'*']),
- when_enabled('show chosen rule'
- for [(rule Rule forward if Cond then Actions)]),
- /* PATCH 10 SEP 90 assert --> asserta for possible TMS in future */
- asserta(already_did(Rule,Cond)), /* tell me you just did it */
- fc_do_rhs(WME,NewWME,Rule,Cond,Actions), /* execute RHS actions */
- when_enabled('show new working memory elements or frame changes'
- for NewWME).
-
- fc_good_potential(RULE,COND,ACTIONS) :- /* a rule enters conflict set if... */
- (rule RULE forward if COND then ACTIONS), /* given this form in database... */
- when_enabled('show single stepping in' for RULE),
- all_in_wm(COND), /* all of its left-hand-side conditions are satisfied */
- when_enabled('show single stepping out' for RULE),
- when_enabled('show history on request' for [RULE,'+']).
-
- fc_do_rhs(WME,NewWME,Rule,Cond,Actions) :- /* case 1: nothing to do */
- Actions = 'no thens',
- NewWME = [halt],
- write('No applicable rules'), nl, /* no applicable rule so halt */
- !.
-
- fc_do_rhs(WME,NewWME,Rule,Cond,Actions) :- /* case 2: normal execution */
- perform(Actions,NewWME,Rule,Cond), /* execute RHS actions */
- !.
-
- fc_do_rhs(WME,NewWME,Rule,Cond,Actions) :- /* case 3: perform/4 failed somehow */
- write('WARNING: rule '),write(Rule),
- write(' right-hand-side action failed. '),
- nl,
- tab11_write(Actions),
- nl,
- NewWME = WME.
-
- fc_halt_else_loop(NewWME) :- /* halt encountered, so finish off */
- ( 'pd624 member'(halt,NewWME) ; currentdb(halt,true) ) ,
- !,
- write('Production system halted'),
- nl. /* end of processing, nothing more to do */
-
- fc_halt_else_loop(NewWME) :- /* no halt, so cause failure-driven loop */
- assert('pd624 wme'(NewWME)),
- fail. /* fail straight back to repeat */
-